home *** CD-ROM | disk | FTP | other *** search
/ Scene 96 / Scene 96 International Edition (Zyklop Software) (Disc 2) (1997).iso / misc / coding / midas060 / src / timer.asm < prev    next >
Encoding:
Assembly Source File  |  1997-01-16  |  27.5 KB  |  1,128 lines

  1. ;*      TIMER.ASM
  2. ;*
  3. ;* TempoTimer
  4. ;*
  5. ;* $Id: timer.asm,v 1.2 1997/01/16 18:41:59 pekangas Exp $
  6. ;*
  7. ;* Copyright 1996,1997 Housemarque Inc.
  8. ;*
  9. ;* This file is part of the MIDAS Sound System, and may only be
  10. ;* used, modified and distributed under the terms of the MIDAS
  11. ;* Sound System license, LICENSE.TXT. By continuing to use,
  12. ;* modify or distribute this file you indicate that you have
  13. ;* read the license and understand and accept it fully.
  14. ;*
  15.  
  16.  
  17. IDEAL
  18. P386
  19. JUMPS
  20.  
  21. INCLUDE "lang.inc"
  22. INCLUDE "mglobals.inc"
  23. INCLUDE "errors.inc"
  24. INCLUDE "timer.inc"
  25. IFNDEF NOEMS
  26. INCLUDE "ems.inc"
  27. ENDIF
  28. INCLUDE "sdevice.inc"
  29.  
  30. ;TIMERBORDERS=1
  31.  
  32. MAXPLAYERS = 16                         ; maximum number of music players
  33.  
  34. NTPRATE = 100                           ; non-tempoPolling SoundDevice
  35.                     ; interrupt rate if not synchronized
  36.                     ; to screen (in Hz)
  37.  
  38. IFDEF __32__
  39. FRAMETIME = 950
  40. ELSE
  41. FRAMETIME = 965         ; Time between two interrupts is 96.5%
  42.                 ; of total frame time - the interrupt comes
  43.                 ; somewhat _before_ the Vertical Retrace
  44.                 ; actually starts.
  45. ENDIF
  46.  
  47.  
  48. ENUM    tmrStates \                     ; timer state
  49.         tmrSystem, \                    ; system timer
  50.         tmrPlayer, \                    ; music player timer
  51.         tmrScreen                       ; Vertical Retrace timer
  52.  
  53.  
  54.  
  55. ;/***************************************************************************\
  56. ;*
  57. ;* Macro:       SetBorder color
  58. ;*
  59. ;* Description: Sets the border color if TIMERBORDERS is defined
  60. ;*
  61. ;* Input:       color           border color
  62. ;*
  63. ;* Destroys:    none
  64. ;*
  65. ;\***************************************************************************/
  66.  
  67. MACRO   SetBorder       color
  68. IFDEF TIMERBORDERS
  69.         push    _dx _ax
  70.     mov    dx,03DAh
  71.     in    al,dx
  72.     mov    dx,03C0h
  73.     mov    al,31h
  74.     out    dx,al
  75.     mov    al,color
  76.     out    dx,al
  77.         pop     _ax _dx
  78. ENDIF
  79. ENDM
  80.  
  81.  
  82.  
  83.  
  84. ;/***************************************************************************\
  85. ;*
  86. ;* Macro:       WaitNextVR
  87. ;*
  88. ;* Description: Waits for next Vertical Retrace
  89. ;*
  90. ;\***************************************************************************/
  91.  
  92. MACRO   WaitNextVR
  93. LOCAL    w1, w2
  94.  
  95.     mov    dx,03DAh
  96. w1:    in    al,dx        ; wait for a non-retrace period
  97.     test    al,8
  98.     jnz    w1
  99.  
  100. w2:    in    al,dx
  101.     test    al,8        ; wait for retrace
  102.     jz    w2
  103. ENDM
  104.  
  105.  
  106.  
  107.  
  108. DATASEG
  109.  
  110.  
  111. D_farptr systemTimer                    ; pointer to system timer routine
  112. sysTmrCount    DD    ?        ; system timer counter
  113.  
  114. playCount    DD    ?        ; player timer counter
  115. playTmrCount    DD    ?        ; initial value for player timer count
  116. D_ptr sdev                              ; pointer to Sound Device
  117.  
  118. musicPlayers    DD      MAXPLAYERS DUP(?)       ; music player routines
  119.  
  120. D_int playSD                            ; 1 if sound should be played
  121. D_int plTimer                           ; 1 if player-timer is active
  122. D_int plError                           ; music playing error code
  123. D_int plCallMP                          ; call music player?
  124.  
  125. scrCount    DD    ?        ; Retrace timer counter
  126. scrTmrCount    DD    ?        ; initial value for VR timer counter
  127. scrPVCount    DD    ?        ; timer count for time before Retrace
  128. D_ptr preVR                             ; pre-VR function
  129. D_ptr immVR                             ; immVR()
  130. D_ptr inVR                              ; inVR()
  131. D_int scrSync                           ; 1 if timer is synchronized to screen
  132. D_int scrTimer                          ; 1 if screen-timer is active
  133. D_int scrPlayer                         ; synchronize player to screen?
  134.  
  135. D_int tmrState                          ; timer state
  136.  
  137. D_int sysTimer                          ; system timer active?
  138.  
  139. IFNDEF __PASCAL__
  140. D_int tmrActive                         ; running in timer interrupt? (global)
  141. ENDIF
  142.  
  143.  
  144.  
  145.  
  146. CODESEG
  147.  
  148.  
  149.  
  150. ;/***************************************************************************\
  151. ;*
  152. ;* Function:    setCount
  153. ;*
  154. ;* Description: Set timer count and restart timer
  155. ;*
  156. ;* Input:       bx              timer count
  157. ;*
  158. ;* Destroys:    al
  159. ;*
  160. ;\***************************************************************************/
  161.  
  162. PROC NOLANGUAGE setCount     NEAR    ; set timer counter and restart
  163.  
  164.     mov    al,30h            ; counter mode 0 - interrupt on
  165.     out    43h,al            ; terminal count
  166.     mov    al,bl
  167.     out    40h,al            ; set timer count and restart timer
  168.     mov    al,bh
  169.     out    40h,al
  170.  
  171.     ret
  172. ENDP
  173.  
  174.  
  175.  
  176.  
  177. ;/***************************************************************************\
  178. ;*
  179. ;* Function:    nextTimer
  180. ;*
  181. ;* Description: Prepare for next timer interrupt
  182. ;*
  183. ;* Destroys:    eax, ebx
  184. ;*
  185. ;\***************************************************************************/
  186.  
  187. PROC NOLANGUAGE nextTimer    NEAR
  188.  
  189.     cmp    [scrSync],1        ; is timer synchronized to screen?
  190.     jne    @@noscr
  191.  
  192.         cmp     [playSD],1              ; should sound be played?
  193.     jne    @@scr
  194.  
  195.     mov    ebx,[playCount]     ; player timer count
  196.     or    ebx,ebx         ; negative
  197.     jns    @@nos1
  198.     mov    ebx,10            ; make sure count is not negative
  199.     mov    [playCount],10
  200.     jmp    @@setpl
  201. @@nos1:
  202.     cmp    ebx,[scrCount]        ; will player timer come before scr?
  203.     jl    @@setpl
  204.  
  205. @@scr:    mov    ebx,[scrCount]        ; screen timer count
  206.     or    ebx,ebx         ; negative?
  207.     jns    @@nos2
  208.     mov    ebx,10            ; make sure count is not negative
  209.     mov    [scrCount],10
  210. @@nos2:
  211.     mov    [tmrState],tmrScreen    ; next interrupt will be screen timer
  212.     call    setCount        ; set count and restart timer
  213.     jmp    @@done
  214.  
  215.  
  216. @@setpl:
  217.     mov    [tmrState],tmrPlayer    ; next interrupt will be player
  218.     call    setCount        ; set count and restart
  219.     jmp    @@done
  220.  
  221.  
  222. @@noscr:
  223.         cmp     [playSD],1              ; should sound be played?
  224.     jne    @@sys
  225.  
  226.     mov    [tmrState],tmrPlayer
  227.     mov    ebx,[playCount]     ; player timer count
  228.     or    ebx,ebx         ; negative?
  229.     jns    @@1
  230.  
  231.     mov    ebx,10            ; make sure count is not negative
  232.     mov    [playCount],10
  233.  
  234. @@1:    call    setCount
  235.     jmp    @@done
  236.  
  237.  
  238. @@sys:                    ; system timer only
  239.     mov    [tmrState],tmrSystem    ; next int is system timer
  240.         xor     _bx,_bx
  241.     call    setCount        ; set system timer count
  242.  
  243. @@done:
  244.     ret
  245. ENDP
  246.  
  247.  
  248.  
  249.  
  250. ;/***************************************************************************\
  251. ;*
  252. ;* Function:    timer
  253. ;*
  254. ;* Description: timer interrupt handler
  255. ;*
  256. ;\***************************************************************************/
  257.  
  258. PROC NOLANGUAGE timer            ; timer interrupt
  259.  
  260.     pushad
  261.     push    ds es fs gs
  262.  
  263.         SetBorder 15
  264.  
  265.         mov     ax,DGROUP
  266.     mov    ds,ax            ; set valid values to segment
  267.         mov     es,ax                   ; registers
  268.  
  269.         mov     [tmrActive],1           ; in timer interrupt
  270.  
  271.     cmp    [tmrState],tmrScreen    ; screen timer interrupt?
  272.     je    @@scrtmr
  273.     cmp    [tmrState],tmrSystem    ; system timer only?
  274.     je    @@systmr
  275.     cmp    [tmrState],tmrPlayer    ; player timer?
  276.     je    @@plrtmr
  277.     jmp    @@systmr        ; do _something_
  278.  
  279.  
  280. @@scrtmr:
  281.     cli                ; no interrupts here!
  282.  
  283.     SetBorder 14
  284.  
  285.     cmp    [scrTimer],1        ; is screen timer already active?
  286.     jne    @@scrnot
  287.  
  288.     ; screen timer already active - PANIC!
  289.  
  290.     mov    eax,[scrCount]
  291.     add    eax,[scrPVCount]
  292.     sub    [playCount],eax     ; update player timer counter
  293.     add    [sysTmrCount],eax    ; update system timer counter
  294.  
  295.     mov    eax,[scrTmrCount]    ; reset screen timer counter
  296.     mov    [scrCount],eax
  297.  
  298.     call    nextTimer        ; next timer interrupt
  299.  
  300.     mov    al,20h            ; send End Of Interrupt
  301.     out    20h,al
  302.     sti                ; enable interrupts
  303.     jmp    @@done            ; stop processing this interrupt
  304.  
  305.  
  306. @@scrnot:
  307.     cmp    [scrSync],1        ; should timer be synchronized to
  308.     jne    @@chksys        ; screen?
  309.  
  310.     mov    [scrTimer],1        ; screen-timer is now active
  311.  
  312.     mov    dx,03DAh
  313. @@wnvr: in    al,dx            ; wait until we are _not_ in a
  314.     test    al,8            ; retrace (just to make sure...)
  315.     jnz    @@wnvr
  316.  
  317.     cmp    [preVR],0
  318.         je      @@npvr                  ; call preVR() if pointer is not
  319.         call    [_ptr preVR] LANG       ; NULL
  320. @@npvr:
  321.  
  322.     SetBorder 1
  323.     mov    eax,[scrCount]
  324.     add    eax,[scrPVCount]    ; update timer counters
  325.     add    [sysTmrCount],eax
  326.  
  327.     cmp    [scrPlayer],1        ; synchronize player to screen?
  328.     je    @@syncpl
  329.     sub    [playCount],eax     ; no, update count
  330.     jmp    @@scd
  331.  
  332. @@syncpl:
  333.     mov    eax,[playTmrCount]    ; synchronize player
  334.     mov    [playCount],eax
  335.  
  336. @@scd:
  337.     mov    eax,[scrTmrCount]    ; reset screen-interrupt count
  338.     mov    [scrCount],eax
  339.  
  340.     mov    dx,03DAh
  341. @@wvr:    in    al,dx            ; wait for the retrace
  342.     test    al,8
  343.     jz    @@wvr
  344.  
  345.         cmp     [immVR],0
  346.         je      @@nivr                  ; call immVR() if pointer is not
  347.         call    [_ptr immVR] LANG       ; NULL
  348.  
  349. @@nivr:
  350.     SetBorder 2
  351.  
  352.     call    nextTimer        ; next timer iterrupt
  353.  
  354.     mov    [scrTimer],0        ; screen-timer (almost) finished
  355.  
  356.     SetBorder 4
  357.  
  358.     sti                ; enable interrupts now
  359.  
  360.     mov    al,20h            ; send End Of Interrupt to Interrupt
  361.     out    20h,al            ; Controller
  362.  
  363.  
  364.         cmp     [inVR],0
  365.         je      @@nvr                   ; call inVR() if pointer is not NULL
  366.         call    [_ptr inVR] LANG
  367.  
  368. @@nvr:
  369.     SetBorder 0
  370.     mov    [scrTimer],0
  371.     jmp    @@chksys        ; check if system timer should be
  372.                     ; called
  373.  
  374.  
  375.  
  376.  
  377.  
  378. @@plrtmr:
  379.         ;SetBorder 7
  380.     cmp    [plTimer],1        ; is player timer already active?
  381.     jne    @@plnot         ; if not, it's OK to continue
  382.  
  383.     ; player timer already active - PANIC!
  384.  
  385.     mov    eax,[playCount]     ; previous player timer count
  386.     sub    [scrCount],eax        ; update screen timer count
  387.     add    [sysTmrCount],eax    ; and system timer count
  388.     mov    eax,[playTmrCount]    ; reset player timer count
  389.     mov    [playCount],eax
  390.     call    nextTimer        ; next timer interrupt (hopefully
  391.                     ; not player anymore...)
  392.     sti                ; enable interrupts
  393.     mov    al,20h            ; send End Of Interrupt
  394.     out    20h,al
  395.     jmp    @@done            ; quit interrupt - no playing until
  396.                     ; the previous player interrupt has
  397.                     ; finished
  398.  
  399. @@plnot:
  400.         mov     [plTimer],1             ; player timer is active
  401.     mov    eax,[playCount]     ; player timer count
  402.     or    eax,eax
  403.     js    @@pn1
  404.     sub    [scrCount],eax        ; update screen timer count
  405.     add    [sysTmrCount],eax    ; increase system timer count
  406. @@pn1:
  407.     cmp    [scrPlayer],1        ; synchronize player to screen?
  408.     je    @@pspl
  409.     mov    ebx,[playTmrCount]    ; new player timer count
  410.     mov    [playCount],ebx     ; set player timer count to counter
  411.     jmp    @@pnt
  412. @@pspl:
  413.         mov     [playCount],0FFFFh      ; make sure that next interrupt will
  414. @@pnt:                    ; be screen, not timer
  415.  
  416.     call    nextTimer        ; next timer interrupt
  417.  
  418.     sti                ; enable interrupts
  419.     mov    al,20h            ; send End Of Interrupt to Interrupt
  420.     out    20h,al            ; Controller
  421.  
  422.         cmp     [playSD],1              ; should music be played?
  423.     je    @@playmus
  424.  
  425.     mov    [plTimer],0        ; player timer not active
  426.     jmp    @@chksys        ; call system timer if appropriate
  427.  
  428. @@playmus:
  429.         cmp     [plError],0             ; error during playing?
  430.         jne     @@pl1
  431.  
  432.     mov    edi,[playTmrCount]    ; store player timer count
  433.  
  434.         ; Start playing loop: (usually updates DMA position)
  435.         LOADPTR es,_si,[sdev]
  436.         call    [_essi+SoundDevice.StartPlay] LANG
  437.         test    _ax,_ax
  438.         jnz     @@plerr
  439.  
  440.         SetBorder 14
  441.  
  442. IFNDEF NOEMS
  443.         cmp     [mUseEMS],1             ; is EMS used?
  444.     jne    @@play
  445.     call    emsSave LANG        ; save EMS mappings
  446.         test    _ax,_ax
  447.         jnz     @@plerr
  448.  
  449.         call    emsSafe LANG            ; set EMS "safe"-flag on
  450.         test    _ax,_ax
  451.         jnz     @@plerr
  452. ENDIF
  453.  
  454. @@play:
  455.     SetBorder 15
  456.         ; Update Sound Device registers / mix data:
  457.         LOADPTR es,_si,[sdev]
  458. IFDEF __16__
  459.         call    [_essi+SoundDevice.Play] LANG, seg plCallMP offset plCallMP
  460. ELSE
  461.         call    [_essi+SoundDevice.Play] LANG, ptr_to plCallMP
  462. ENDIF
  463.     SetBorder 2
  464.         test    _ax,_ax
  465.         jnz     @@plerr
  466.  
  467.         cmp     [plCallMP],1            ; should music player be called?
  468.         jne     @@noplay
  469.  
  470.         lea     _si,[musicPlayers]      ; point ds:si to music players
  471.  
  472. @@playmusic:
  473.         cmp     [_ptr _si],0            ; is current music player zero?
  474.         je      @@nothispl              ; if is, do not play
  475.  
  476.         call    [_ptr _si] LANG         ; play music
  477.         test    _ax,_ax
  478.         jnz     @@plerr
  479.  
  480. @@nothispl:
  481.         add     _si,4
  482.         cmp     _si,(offset musicPlayers) + 4*MAXPLAYERS
  483.         jb      @@playmusic
  484.  
  485.         LOADPTR es,_si,[sdev]
  486.         cmp     [_essi+SoundDevice.tempoPoll],0         ; poll again if
  487.     je    @@play            ; tempoPoll flag is zero
  488.  
  489. @@noplay:
  490. IFNDEF NOEMS
  491.         cmp     [mUseEMS],1
  492.     jne    @@nems1
  493.     SetBorder 14
  494.     call    emsStopSafe LANG
  495.         test    _ax,_ax
  496.         jnz     @@plerr
  497.  
  498.     call    emsRestore LANG
  499.         test    _ax,_ax
  500.         jnz     @@plerr
  501. ENDIF
  502.  
  503. @@nems1:
  504.     SetBorder 0
  505.  
  506.         LOADPTR es,_si,[sdev]
  507.         cmp     [_essi+SoundDevice.tempoPoll],1         ; no need to change
  508.     jne    @@pl1            ; timer rate if tempoPoll is zero.
  509.  
  510.     cmp    [playTmrCount],edi    ; has player timer count been changed?
  511.     je    @@pl1
  512.  
  513.         mov     ebx,[playTmrCount]
  514.         mov     [playCount],ebx         ; set new player timer count
  515.         cmp     [tmrState],tmrPlayer    ; would next interrupt be player?
  516.         jne     @@pl1
  517.         call    nextTimer               ; if so, set new count
  518.  
  519.         jmp     @@pl1
  520.  
  521. @@plerr:
  522.         mov     [plError],_ax           ; playing error
  523.  
  524. @@pl1:    mov    [plTimer],0        ; player timer finished
  525.  
  526.  
  527. @@chksys:                ; check system timer
  528.     sti
  529.     cmp    [sysTmrCount],10000h    ; should system timer be called?
  530.     jb    @@done
  531.  
  532.     mov    eax,[sysTmrCount]
  533.     sub    eax,10000h        ; substract 65536 from system timer
  534.     or    eax,eax         ; count. Is the result negative?
  535.     jns    @@stcok         ; (SHOULD not be)
  536.     xor    eax,eax         ; negative - set to zero
  537. @@stcok:
  538.     mov    [sysTmrCount],eax    ; new timer count
  539. IFDEF __16__
  540.         pushf
  541. ELSE
  542.         pushfd
  543. ENDIF
  544.         call    [_farptr systemTimer]   ; call system timer
  545.     jmp    @@chksys
  546.  
  547.  
  548.  
  549. @@systmr:                ; system timer only
  550.     sti
  551.         xor     _bx,_bx                 ; set new timer count and restart
  552.     call    setCount
  553. IFDEF __16__
  554.         pushf
  555. ELSE
  556.         pushfd
  557. ENDIF
  558.         call    [_farptr systemTimer]   ; call system timer
  559.  
  560.  
  561. @@done:
  562.         mov     [tmrActive],0           ; not in timer interrupt
  563.         SetBorder 0
  564.         pop     gs fs es ds             ; restore registers
  565.     popad
  566.         nop                             ; avoid the popad-bug...
  567. IFDEF __16__
  568.     iret
  569. ELSE
  570.         iretd
  571. ENDIF
  572. ENDP
  573.  
  574.  
  575.  
  576.  
  577. ;/***************************************************************************\
  578. ;*
  579. ;* Function:     int tmrGetScrSync(unsigned *scrSync);
  580. ;*
  581. ;* Description:  Calculates the screen synchronization value for timer
  582. ;*
  583. ;* Input:        unsigned *scrSync       pointer to screen synchronization
  584. ;*                                       value
  585. ;*
  586. ;* Returns:      MIDAS error code.
  587. ;*               Screen syncronization value used with tmrSyncScr() is stored
  588. ;*               in *scrSync.
  589. ;*
  590. ;\***************************************************************************/
  591.  
  592. PROC    tmrGetScrSync   _funct  PscrSync : _ptr
  593. LOCAL   tmrVal : _int
  594.  
  595.     cli                ; disable interrupts for maximum
  596.                     ; accuracy
  597. @@read:
  598.         xor     _ax,_ax
  599.     WaitNextVR            ; wait for next Vertical Retrace
  600.  
  601.     mov    al,36h
  602.     out    43h,al
  603.     xor    al,al            ; reset the timer
  604.     out    40h,al
  605.     out    40h,al
  606.  
  607.  
  608.     WaitNextVR            ; wait for next Vertical Retrace
  609.  
  610.     xor    al,al
  611.     out    43h,al
  612.     in    al,40h
  613.     mov    ah,al
  614.     in    al,40h            ; read timer count - time between
  615.     xchg    al,ah            ; two Vertical Retraces
  616.         neg     ax
  617.         mov     [tmrVal],_ax
  618.  
  619.         xor     _ax,_ax
  620.     WaitNextVR            ; wait for next Vertical Retrace
  621.  
  622.     mov    al,36h
  623.     out    43h,al
  624.     xor    al,al            ; reset timer again
  625.     out    40h,al
  626.     out    40h,al
  627.  
  628.  
  629.     WaitNextVR            ; wait...
  630.  
  631.     xor    al,al
  632.     out    43h,al
  633.     in    al,40h
  634.     mov    ah,al            ; and read the timer count again
  635.     in    al,40h
  636.     xchg    al,ah
  637.         neg     ax
  638.  
  639.         mov     _dx,_ax
  640.  
  641.         sub     _dx,[tmrVal]
  642.         cmp     _dx,2                   ; If the difference between the two
  643.     jg    @@read            ; values read was >2, read again.
  644.         cmp     _dx,-2
  645.     jl    @@read
  646.  
  647.         sti                             ; enable interrupts
  648.  
  649.         LOADPTR es,_bx,[PscrSync]       ; store time in *scrSync
  650.         mov     [_esbx],_ax
  651.  
  652.         xor     _ax,_ax                 ; success
  653.  
  654.     ret
  655. ENDP
  656.  
  657.  
  658.  
  659.  
  660. ;/***************************************************************************\
  661. ;*
  662. ;* Function:     int tmrInit(void);
  663. ;*
  664. ;* Description:  Initializes TempoTimer.
  665. ;*
  666. ;* Returns:      MIDAS error code
  667. ;*
  668. ;\***************************************************************************/
  669.  
  670. PROC    tmrInit         _funct
  671.  
  672.     mov    [tmrState],tmrSystem    ; only system timer now
  673.         mov     [playSD],0
  674.     mov    [scrSync],0
  675.     mov    [plTimer],0
  676.     mov    [scrTimer],0
  677.     mov    [sysTmrCount],0
  678.     mov    [sysTimer],0
  679.         mov     [plError],0
  680.  
  681. IFDEF __32__
  682.         push    es
  683. ENDIF
  684.  
  685.     mov    ax,3508h
  686.     int    21h
  687. IFDEF __16__
  688.         mov     [word systemTimer],bx   ; save system timer interrupt
  689.     mov    [word systemTimer+2],es
  690. ELSE
  691.         mov     [dword systemTimer],ebx ; save system timer interrupt
  692.         mov     [word systemTimer+4],es
  693. ENDIF
  694.  
  695. IFDEF __32__
  696.         pop     es
  697. ENDIF
  698.  
  699.     push    ds
  700. ;        mov     ax,seg timer
  701.         mov     ax,cs
  702.     mov    ds,ax            ; set new timer interrupt
  703.         mov     _dx,offset timer
  704.     mov    ax,2508h
  705.     int    21h
  706.     pop    ds
  707.  
  708.         xor     _bx,_bx                 ; set timer count and restart
  709.     call    setCount
  710.  
  711.         SetBorder 2
  712.  
  713.         xor     _ax,_ax                 ; success
  714.     ret
  715. ENDP
  716.  
  717.  
  718.  
  719.  
  720. ;/***************************************************************************\
  721. ;*
  722. ;* Function:     int tmrClose(void);
  723. ;*
  724. ;* Description:  Uninitializes TempoTimer. MUST be called if and ONLY if
  725. ;*               tmrInit() has been called.
  726. ;*
  727. ;* Returns:      MIDAS error code
  728. ;*
  729. ;\***************************************************************************/
  730.  
  731. PROC    tmrClose        _funct
  732.  
  733.     mov    al,36h            ; DOS default timer mode
  734.     out    43h,al
  735.     xor    al,al            ; set timer count to 65536 - 18.2Hz
  736.     out    40h,al            ; (DOS default)
  737.     out    40h,al
  738.  
  739.     push    ds
  740.     mov    ax,2508h
  741.         lds     _dx,[systemTimer]       ; restore system timer interrupt
  742.     int    21h
  743.     pop    ds
  744.  
  745.     mov    al,36h            ; DOS default timer mode
  746.     out    43h,al
  747.     xor    al,al            ; set timer again for safety
  748.     out    40h,al
  749.     out    40h,al
  750.  
  751.         xor     _ax,_ax                 ; success
  752.     ret
  753. ENDP
  754.  
  755.  
  756.  
  757.  
  758. ;/***************************************************************************\
  759. ;*
  760. ;* Function:    int tmrPlaySD(SoundDevice *SD);
  761. ;*
  762. ;* Description: Starts playing sound with a Sound Device ie. calling its
  763. ;*              Play() function in the update rate, which is set to
  764. ;*              50Hz.
  765. ;*
  766. ;* Input:       SoundDevice *SD         Sound Device that will be used
  767. ;*
  768. ;* Returns:     MIDAS error code.
  769. ;*
  770. ;\***************************************************************************/
  771.  
  772. PROC    tmrPlaySD       _funct  SD : _ptr
  773. USES    _di
  774.  
  775.         mov     eax,[SD]                ; save Sound Device pointer
  776.     mov    [sdev],eax
  777.  
  778.         lea     _di,[musicPlayers]
  779.         mov     ax,ds
  780.         mov     es,ax                   ; reset music player pointers
  781.         xor     al,al                   ; to NULL - no music players
  782.         mov     _cx,MAXPLAYERS * PTRSIZE
  783.         cld
  784.         rep     stosb
  785.  
  786.     cli                ; disable interrupts for a while
  787.  
  788.         LOADPTR es,_di,[sdev]
  789.         cmp     [_esdi+SoundDevice.tempoPoll],1
  790.     je    @@tempo         ; use tempo-polling?
  791.  
  792.     cmp    [scrSync],0        ; synchronize to screen?
  793.     je    @@noss
  794.     mov    eax,25            ; yes - synchronize also player
  795.     mul    [scrTmrCount]        ; interrupt count = 1/4 of screen
  796.     mov    ebx,100         ; interrupt count (player interrupt
  797.     div    ebx            ; will come somewhat after Vertical
  798.     mov    ebx,eax         ; Retrace end)
  799.     mov    [scrPlayer],1        ; synchronize player to screen
  800.     jmp    @@1
  801.  
  802. @@noss:
  803.     mov    ebx,1193180/NTPRATE    ; set polling rate to NTPRATE Hz
  804.                     ; (default 100Hz)
  805.     mov    [scrPlayer],0        ; don't synchronize to screen
  806.     jmp    @@1
  807. @@tempo:
  808.         mov     ebx,1193180/50          ; tempo-polling - set update rate to
  809.         mov     [scrPlayer],0           ; 50Hz, don't synchronize to screen
  810. @@1:
  811.     mov    [playTmrCount],ebx    ; player timer count
  812.     mov    [playCount],ebx
  813.         mov     [playSD],1              ; playing sound
  814.         mov     [plTimer],0             ; player timer not active
  815.         mov     [plError],0             ; no error during playing
  816.  
  817.     cmp    [tmrState],tmrSystem    ; is only system timer running?
  818.     jne    @@noset         ; if not, don't set count and restart
  819.  
  820.     mov    [tmrState],tmrPlayer    ; next interrupt will be player int
  821.     call    setCount
  822.     mov    [sysTmrCount],0
  823.  
  824. @@noset:
  825.     sti
  826.  
  827.         SetBorder 3
  828.  
  829.         xor     _ax,_ax                 ; success
  830.     ret
  831. ENDP
  832.  
  833.  
  834.  
  835.  
  836. ;/***************************************************************************\
  837. ;*
  838. ;* Function:    int tmrStopSD(void);
  839. ;*
  840. ;* Description: Stops playing sound with the Sound Device.
  841. ;*
  842. ;* Returns:     MIDAS error code.
  843. ;*
  844. ;\***************************************************************************/
  845.  
  846. PROC    tmrStopSD       _funct
  847.  
  848.     cli
  849.  
  850.         mov     [playSD],0
  851.     cmp    [scrSync],0        ; is timer synchronized to screen?
  852.     jne    @@noset         ; if is, don't force system timer
  853.  
  854.     mov    [tmrState],tmrSystem    ; only system timer now
  855.         xor     _bx,_bx
  856.     call    setCount
  857.  
  858. @@noset:
  859.     sti
  860.  
  861.         xor     _ax,_ax                 ; success
  862.     ret
  863. ENDP
  864.  
  865.  
  866.  
  867.  
  868. ;/***************************************************************************\
  869. ;*
  870. ;* Function:    int tmrPlayMusic(void *play, int *playerNum);
  871. ;*
  872. ;* Description: Starts playing music with the timer.
  873. ;*
  874. ;* Input:       void *play              Pointer to music playing function.
  875. ;*                                      Must return MIDAS error codes
  876. ;*              int *playerNum          Pointer to player number, used
  877. ;*                                      for stopping music
  878. ;*
  879. ;* Returns:     MIDAS error code. Player number is written to *playerNum.
  880. ;*
  881. ;* Notes:       There can be a maximum of 16 music players active at the
  882. ;*              same time.
  883. ;*
  884. ;\****************************************************************************/
  885.  
  886. PROC    tmrPlayMusic    _funct  play : _ptr, playerNum : _ptr
  887.  
  888.         mov     eax,[play]
  889.         lea     _bx,[musicPlayers]      ; point bx to music player ptrs
  890.         xor     _cx,_cx                 ; cx = player number
  891.  
  892.         ; Find free music player slot or return errOutOfResources if none
  893.         ; left:
  894. @@search:
  895.         cmp     [_ptr _bx],0            ; is current player slot free?
  896.         je      @@free
  897.         add     _bx,PTRSIZE
  898.         inc     _cx                     ; next player number
  899.         cmp     _cx,MAXPLAYERS          ; past the limit?
  900.         jb      @@search
  901.  
  902.         mov     _ax,errOutOfResources
  903.         jmp     @@err
  904.  
  905. @@free:
  906.         mov     [_bx],eax               ; free player number found (in cx)
  907.         LOADPTR es,_bx,[playerNum]      ; write player number to
  908.         mov     [_esbx],_cx             ; *playerNum
  909.  
  910.         xor     _ax,_ax
  911.         jmp     @@done
  912.  
  913. @@err:
  914.         ERROR   ID_tmrPlayMusic
  915.  
  916. @@done:
  917.         ret
  918. ENDP
  919.  
  920.  
  921.  
  922.  
  923. ;/***************************************************************************\
  924. ;*
  925. ;* Function:    int tmrStopMusic(int playerNum);
  926. ;*
  927. ;* Description: Stops playing music with the timer.
  928. ;*
  929. ;* Input:       int playerNum           Number of player to be stopped.
  930. ;*
  931. ;* Returns:     MIDAS error code
  932. ;*
  933. ;\***************************************************************************/
  934.  
  935. PROC    tmrStopMusic    _funct  playerNum : _int
  936.  
  937.         mov     _bx,[playerNum]         ; write NULL to player pointer to
  938.         shl     _bx,2                   ; mark it free
  939.         mov     [_ptr musicPlayers+_bx],0
  940.  
  941.         xor     _ax,_ax
  942.  
  943.         ret
  944. ENDP
  945.  
  946.  
  947.  
  948.  
  949. ;/***************************************************************************\
  950. ;*
  951. ;* Function:    int tmrSyncScr(unsigned sync, void (*preVR)(),
  952. ;*                  void (*immVR)(), void (*inVR)());
  953. ;*
  954. ;* Description: Synchronizes the timer to screen refresh.
  955. ;*
  956. ;* Input:       unsigned sync           Screen synchronization value returned
  957. ;*                                      by tmrGetScrSync().
  958. ;*              void (*preVR)()         Pointer to the routine that will be
  959. ;*                                      called BEFORE Vertical Retrace
  960. ;*              void (*immVR)()         Pointer to the routine that will be
  961. ;*                                      called immediately after Vertical
  962. ;*                                      Retrace starts
  963. ;*              void (*inVR)()          Pointer to the routine that will be
  964. ;*                                      called some time during Vertical
  965. ;*                                      Retrace
  966. ;*
  967. ;* Returns:     MIDAS error code
  968. ;*
  969. ;* Notes:       preVR() and immVR() functions must be as short as possible
  970. ;*              and do nothing else than update counters or set some VGA
  971. ;*              registers to avoid timer synchronization problems. inVR()
  972. ;*              can take a longer time and can be used for, for example,
  973. ;*              setting the palette.
  974. ;*
  975. ;*              Remember to use the correct calling convention for the xxVR()
  976. ;*              routines! (pascal for Pascal programs, cdecl otherwise).
  977. ;*
  978. ;\***************************************************************************/
  979.  
  980. PROC    tmrSyncScr      _funct  sync : _int, PpreVR : _ptr, PimmVR : _ptr, \
  981.                                 PinVR : _ptr
  982. USES    _si
  983.  
  984.     cli                ; make sure we won't be disturbed...
  985.  
  986.         mov     eax,[PpreVR]
  987.     mov    [preVR],eax
  988.         mov     eax,[PimmVR]            ; store function pointers
  989.         mov     [immVR],eax
  990.         mov     eax,[PinVR]
  991.         mov     [inVR],eax
  992.  
  993.     mov    [scrSync],1        ; synchronize to screen
  994.     mov    [scrTimer],0        ; screen timer is not active
  995.  
  996. IFDEF __16__
  997.         xor     eax,eax
  998. ENDIF
  999.         mov     _ax,FRAMETIME
  1000.     mul    [sync]            ; time between two screen interrupts
  1001.         mov     _bx,1000                ; is FRAMETIME/10 % of total frame
  1002.         div     _bx                     ; time
  1003.  
  1004.     shr    eax,1
  1005.     mov    [scrCount],eax        ; screen timer counter
  1006.     mov    [scrTmrCount],eax
  1007.     mov    ebx,eax
  1008.  
  1009. IFDEF __16__
  1010.         xor     eax,eax
  1011. ENDIF
  1012.         mov     _ax,[sync]
  1013.     shr    eax,1            ; scrPVCount = timer count between
  1014.     sub    eax,ebx         ; interrupt and start of Vertical
  1015.     mov    [scrPVCount],eax    ; Retrace
  1016.  
  1017.     mov    [tmrState],tmrScreen    ; next timer interrupt is screen timer
  1018.     WaitNextVR            ; wait for next retrace
  1019.     call    setCount        ; set count and restart timer
  1020.  
  1021.     sti
  1022.  
  1023.  
  1024.         cmp     [playSD],0              ; is sound being played?
  1025.     je    @@nomsync
  1026.  
  1027.         LOADPTR es,_si,[sdev]                   ; do not synchronize player
  1028.         cmp     [_essi+SoundDevice.tempoPoll],1 ; interrupt to screen if
  1029.     je    @@nomsync            ; tempo-polling is used
  1030.  
  1031.     mov    eax,25
  1032.     mul    [scrTmrCount]        ; interrupt count = 1/4 of screen
  1033.     mov    ebx,100         ; interrupt count (player interrupt
  1034.     div    ebx            ; will come somewhat after Vertical
  1035.     mov    ebx,eax         ; Retrace end)
  1036.     mov    [scrPlayer],1        ; synchronize player to screen
  1037.  
  1038.     mov    [playTmrCount],ebx    ; player timer count
  1039.     mov    [playCount],ebx
  1040.  
  1041. @@nomsync:
  1042.         xor     _ax,_ax                 ; success
  1043.     ret
  1044. ENDP
  1045.  
  1046.  
  1047.  
  1048.  
  1049. ;/***************************************************************************\
  1050. ;*
  1051. ;* Function:     int tmrStopScrSync(void);
  1052. ;*
  1053. ;* Description:  Stops synchronizing the timer to the screen.
  1054. ;*
  1055. ;* Returns:      MIDAS error code
  1056. ;*
  1057. ;\***************************************************************************/
  1058.  
  1059. PROC    tmrStopScrSync  _funct
  1060.  
  1061.     cli
  1062.  
  1063.     cmp    [scrPlayer],1        ; is player being synchronized to
  1064.     jne    @@nospl         ; screen?
  1065.  
  1066.     mov    ebx,1193180/NTPRATE    ; set polling rate to NTPRATE Hz
  1067.                     ; (default 100Hz)
  1068.     mov    [playTmrCount],ebx    ; player timer count
  1069.     mov    [playCount],ebx
  1070.     mov    [scrPlayer],0        ; don't synchronize to screen
  1071.  
  1072. @@nospl:
  1073.     mov    [scrSync],0        ; no screen synchronization
  1074.     mov    [scrTimer],0        ; screen timer is not active
  1075.     call    nextTimer        ; set timer count and restart
  1076.  
  1077.     sti
  1078.  
  1079.         xor     _ax,_ax                 ; success
  1080.     ret
  1081. ENDP
  1082.  
  1083.  
  1084.  
  1085.  
  1086. ;/***************************************************************************\
  1087. ;*
  1088. ;* Function:     int tmrSetUpdRate(unsigned updRate);
  1089. ;*
  1090. ;* Description:  Sets the timer update rate, ie. the rate at which the music
  1091. ;*               playing routine is called
  1092. ;*
  1093. ;* Input:        unsigned updRate       updating rate, in 100*Hz (5000=50Hz)
  1094. ;*
  1095. ;* Returns:      MIDAS error code
  1096. ;*
  1097. ;\***************************************************************************/
  1098.  
  1099. PROC    tmrSetUpdRate   _funct  updRate : _int
  1100.  
  1101.         LOADPTR es,_bx,[sdev]
  1102.         cmp     [_esbx+SoundDevice.tempoPoll],0         ; don't change rate
  1103.         je      @@done                                  ; if tempoPoll == 0
  1104.  
  1105.         mov     eax,119318000
  1106.         xor     edx,edx                 ; eax = new timer count
  1107. IFDEF __16__
  1108.         xor     ebx,ebx
  1109. ENDIF
  1110.         mov     _bx,[updRate]
  1111.         div     ebx
  1112.         mov     [playTmrCount],eax
  1113.  
  1114. @@done:
  1115.         xor     _ax,_ax                 ; success
  1116.     ret
  1117. ENDP
  1118.  
  1119.  
  1120. ;* $Log: timer.asm,v $
  1121. ;* Revision 1.2  1997/01/16 18:41:59  pekangas
  1122. ;* Changed copyright messages to Housemarque
  1123. ;*
  1124. ;* Revision 1.1  1996/05/22 20:49:33  pekangas
  1125. ;* Initial revision
  1126. ;*
  1127.  
  1128. END